/*
 * Copyright (c) 2021-2024 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include <math.h>
#include "board.h"
#include "hpm_dac_drv.h"

#define DAC_STEP_CFG_IDX DAC_STEP_CFG_STEP0

#define DAC_BUFF0_COUNT (DAC_SOC_MAX_BUFF_COUNT / 32)  /* 2048 */
#define DAC_BUFF1_COUNT (DAC_SOC_MAX_BUFF_COUNT / 32)  /* 2048 */

#define PI HPM_PI

ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(DAC_SOC_BUFF_ALIGNED_SIZE) static uint32_t buffer0[DAC_BUFF0_COUNT];
ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(DAC_SOC_BUFF_ALIGNED_SIZE) static uint32_t buffer1[DAC_BUFF1_COUNT];

ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(DAC_SOC_BUFF_ALIGNED_SIZE) static uint32_t buffer2[DAC_BUFF0_COUNT];
ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(DAC_SOC_BUFF_ALIGNED_SIZE) static uint32_t buffer3[DAC_BUFF1_COUNT];

typedef enum {
    dac_sin_Waveform = 0,
    dac_cos_Waveform
} dac_Waveform_t;

static void init_common_config(DAC_Type *ptr,dac_mode_t mode)
{
    dac_config_t config;

    dac_get_default_config(&config);
    config.dac_mode = mode;
    if(ptr == HPM_DAC0)
    {
        config.sync_mode = (clk_dac_src_ahb0 == clock_get_source(clock_dac0)) ? true : false;
    }else if(ptr == HPM_DAC1){
        config.sync_mode = (clk_dac_src_ahb0 == clock_get_source(clock_dac1)) ? true : false;
    }

    dac_init(ptr, &config);
}

void dac_set_buffer(uint32_t* buffer_0,uint32_t* buffer_1,dac_Waveform_t Waveform_type)
{
    if(Waveform_type == dac_sin_Waveform)
    {
        /* sine waveform */
        printf("printf sine wavform\r\n");
        for (uint16_t i = 0; i < (DAC_SOC_MAX_DATA + 1) / 2; i += 1) {
            buffer_0[i] = ((DAC_SOC_MAX_DATA + 1) / 2) * sin(i * 2 * 4 * PI / (DAC_SOC_MAX_DATA + 1)) + ((DAC_SOC_MAX_DATA + 1) / 2 - 1);
        
            buffer_1[i] = ((DAC_SOC_MAX_DATA + 1) / 2) * sin(i * 2 * 4 * PI / (DAC_SOC_MAX_DATA + 1)) + ((DAC_SOC_MAX_DATA + 1) / 2 - 1);
        }
        printf("sine buffer[0] = %d\r\n",buffer_0[0]);
    }else if(Waveform_type == dac_cos_Waveform){
        /* cos waveform */
        printf("printf cos wavform\r\n");
        for (uint16_t i = 0; i < (DAC_SOC_MAX_DATA + 1) / 2; i += 1) {
            buffer_0[i] = ((DAC_SOC_MAX_DATA + 1) / 2) * cos(i * 2 * 4 * PI / (DAC_SOC_MAX_DATA + 1)) + ((DAC_SOC_MAX_DATA + 1) / 2 - 1);
        
            buffer_1[i] = ((DAC_SOC_MAX_DATA + 1) / 2) * cos(i * 2 * 4 * PI / (DAC_SOC_MAX_DATA + 1)) + ((DAC_SOC_MAX_DATA + 1) / 2 - 1);
        }
        printf("cos buffer[0] = %d\r\n",buffer_0[0]);
    }
}

static void set_buffer_mode_config(DAC_Type *ptr,dac_Waveform_t Waveform_type)
{
    dac_buffer_config_t buffer_config;

    printf("Set DAC to output data in buffer mode\n");
    printf("DAC is outputting a sine waveform in buffer mode\n");

    buffer_config.buf_data_mode = dac_data_stru_1_point;
    buffer_config.burst = dac_burst_single;

    buffer_config.buf0.stop = 0;
    buffer_config.buf1.stop = 0;

    if(ptr == HPM_DAC0)
    {
        dac_set_buffer(buffer0,buffer1,Waveform_type);
        buffer_config.buf0.start_addr = (uint32_t)buffer0;
        buffer_config.buf0.len = (uint16_t)(sizeof(buffer0) / sizeof(uint32_t));
        
        buffer_config.buf1.start_addr = (uint32_t)buffer1;
        buffer_config.buf1.len = (uint16_t)(sizeof(buffer1) / sizeof(uint32_t));

        dac_set_buffer_config(ptr, &buffer_config);
        dac_set_output_frequency(ptr, clock_get_frequency(clock_dac0), DAC_SOC_MAX_OUTPUT_FREQ);
    }else{
        dac_set_buffer(buffer2,buffer3,Waveform_type);

        buffer_config.buf0.start_addr = (uint32_t)buffer2;
        buffer_config.buf0.len = (uint16_t)(sizeof(buffer0) / sizeof(uint32_t));
        
        buffer_config.buf1.start_addr = (uint32_t)buffer3;
        buffer_config.buf1.len = (uint16_t)(sizeof(buffer1) / sizeof(uint32_t));

        dac_set_buffer_config(ptr, &buffer_config);
        dac_set_output_frequency(ptr, clock_get_frequency(clock_dac1), DAC_SOC_MAX_OUTPUT_FREQ);
    }
}

void DAC_Set_Generate_Waveform(DAC_Type *ptr,dac_Waveform_t Waveform_type)
{
    board_init_dac_clock(ptr, false);
    /* Initialize a DAC pin */
    board_init_dac_pins(ptr);

    init_common_config(ptr,dac_mode_buffer);

    /* Enable DAC conversion */
    dac_enable_conversion(ptr, true);

    set_buffer_mode_config(ptr,Waveform_type);

    
}

void Sin_Cos_WaveForm_Generate(void)
{
    /* Initialize a DAC clock */
    DAC_Set_Generate_Waveform(HPM_DAC0,dac_sin_Waveform);

    DAC_Set_Generate_Waveform(HPM_DAC1,dac_sin_Waveform);

    dac_set_buffer_sw_trigger(HPM_DAC0);

    dac_set_buffer_sw_trigger(HPM_DAC1);
    
}
